<?php
/** 
 * Class is an abstraction of an uploadable file.
 * Gets all information about file.
 * 
 * @package Library
 * @subpackage File 
 * @category File's modules 
 */
class File extends IError
{
    // filesize
    var $size;

    // mime type
    var $mimeType;

    // full path to file
    var $path;

    // uploading limits
    var $limits = array();

    // type of file(exstension)
    var $type;

    // Real name of uploaded file
    var $realName = '';

    /**
     * File
     * Construct function for working with file
     * 
     * @param  $info array with image restrictions
     * @return File
     */
    function File($info = null)
    {
        if (!$info)
            $info = _cfg("file");
        $this->limits['FILE_MAX_SIZE'] = $info['max_size'];
    }

    /**
     * getName
     * This function gets name of the file
     *
     * @return string
     */
    function getName()
    {
        return basename($this->path);
    }
    
    /**
     * loadInfo
     * This function loads info about file: size, type.
     *
     * @param string $path to file
     * @return boolean
     */
    function loadInfo($path)
    {
        if('' == $this->realName)
            $this->realName = $path;

        $this->path = $path;
        if (! file_exists($path))
            return $this->addError('file.not_exist', $path);

        $this->size = filesize($this->path);
        if (!$this->size)
            return $this->addError('file.not_exist', $this->realName);

        if (! $this->type)
            $this->type = subStr($this->path, strrpos($this->path, '.'));
        return true;
    }

    /**
     * move
     * This function moves the file to a new location
     *
     * @param string $dest new location
     */
    function move($dest)
    {
        //@see user comments to php function rename
        if (file_exists($dest)) 
        { 
            unlink($dest);
            rename($this->path, $dest);
        } 
        else 
        { 
            rename($this->path, $dest);
        }

        $this->path = $dest;
    }

    /**
     * upload
     * Uploads file, checks limitations.
     *
     * @param string $formItem name of html form input
     * @param string $destPath destination, with '/' at the end
     * @param string $destName
     * @param string $destExt
     * @return array with file info or false if error
     */
    function upload($formItem, $destPath, $destName='', $destExt='')
    {
        if (!$this->isUploaded($formItem))
            return $this->addError('file.not_uploaded', '');

        $file = File::_buildFile($formItem);
        $this->mimeType = $file['type'];
        $this->realName = $file['name'];

        $this->type = ($destExt ? $destExt : subStr($file['name'], strrpos($file['name'], '.')));

        if (! $this->loadInfo($file['tmp_name']))
            return false;

        if (! $this->_checkLimits())
            return false;

        if (! is_uploaded_file($this->path))
            return $this->addError('file.not_uploaded', $file['name']);

        $dest = $destName ? $destPath.$destName : $destPath.uniqid('f');
        $dest .= '.'.$this->type;
        if (! move_uploaded_file($this->path, $dest) )
            return $this->addError('file.not_moved', $file['name']);

        $this->path = $dest;
        chmod($this->path, 0644);
        return $file;
    }

    /**
     * _buildFile
     * Gets info about file if input name is string like 'name' or array like 'name[ind]'
     *
     * @param name of html form input $formItem
     * @return array file info
     */
    function _buildFile($formItem)
    {
        $file = array();

        if (!$_FILES || !isset($_FILES[$formItem]))
            return $file;
                
        if (! strpos($formItem, ']'))
        {
            $file = $_FILES[$formItem];
        }
        elseif (preg_match('/^(.+)\[(.+)\]$/', $formItem, $aM))
        {
            $file['name']     = $_FILES[$aM[1]]['name'][$aM[2]];
            $file['type']     = $_FILES[$aM[1]]['type'][$aM[2]];
            $file['tmp_name'] = $_FILES[$aM[1]]['tmp_name'][$aM[2]];
            $file['error']    = $_FILES[$aM[1]]['error'][$aM[2]];
            $file['size']     = $_FILES[$aM[1]]['size'][$aM[2]];
        }
        else // fatal error
            IError::fatal('file.invalid_input_name: "'. $formItem.'"');

        return $file;
    }

    /**
     * _checkLimits
     * This function checks limitation
     *
     * @return boolean
     */
    function _checkLimits()
    {
        if ($this->limits['FILE_MAX_SIZE'] && $this->size >= $this->limits['FILE_MAX_SIZE'])
            return $this->addError('file.max_size', array($this->size, $this->limits['FILE_MAX_SIZE']) );
        return true;
    }
    
    /**
     * isUploaded
     * This function checks if file was uploaded by html form with input with given name
     *
     * @param string $formItem input name
     * @return boolean
     */    
    function isUploaded($formItem)
    {
        $file = $this->_buildFile($formItem);
        return ($file && $file['error'] != UPLOAD_ERR_NO_FILE); 
    }

    /**
     * isUpload
     * This function serves to call the function isUploaded.
     *
     * @param string $formItem input name
     * @return boolean
     */    
    function isUpload($formItem)
    {        
        return $this->isUploaded($formItem);
    }

}